package core

import (
	"os"
	"fmt"
	"time"
	"strconv"
	"kumachan/standalone/util/richtext"
)


type CrashKind string
const (
	Undefined CrashKind = "undefined"
	AssertionFailed CrashKind = "assertion failed"
	InvalidArgument CrashKind = "invalid argument"
	MissingNativeFunction CrashKind = "missing native function"
	ErrorInEntryObservable CrashKind = "error occurred in entry observable"
	RunOfCrashObservable CrashKind = "crash"
)

func Crash(h RuntimeHandle, kind CrashKind, msg string) {
	_, _ = fmt.Fprintln(os.Stderr, "*************************")
	var info = h.GetFrameInfo()
	var f = info.CalleeName
	var loc = info.CallLocation
	var b richtext.Block
	b.WriteSpan(fmt.Sprintf("[%s]", time.Now()))
	b.WriteLineFeed()
	b.WriteSpan("Crashed in call of", richtext.TAG_ERR_NORMAL)
	b.WriteSpan(strconv.Quote(f), richtext.TAG_ERR_INLINE)
	b.WriteLineFeed()
	b.Append(loc.FormatMessage(describeCrash(kind, msg)))
	_, _ = fmt.Fprintln(os.Stderr, b.RenderConsole())
	os.Exit(1)
	// noinspection ALL
	panic("process should have exited")
}
func describeCrash(kind CrashKind, msg string) richtext.Block {
	var b richtext.Block
	b.WriteSpan(fmt.Sprintf("%s: ", kind), richtext.TAG_ERR_NORMAL)
	b.WriteSpan(msg, richtext.TAG_ERR_NOTE)
	return b
}

func Crash1[A any] (h RuntimeHandle, kind CrashKind, msg string) A {
	var a A
	Crash(h, kind, msg)
	return a
}

func Crash2[A any, B any] (h RuntimeHandle, kind CrashKind, msg string) (A,B) {
	var a A
	var b B
	Crash(h, kind, msg)
	return a, b
}


